/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.primary_data;

import io.milton.http.Auth;
import io.milton.http.Request;
import io.milton.http.Request.Method;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.resource.CollectionResource;
import io.milton.resource.GetableResource;
import io.milton.resource.PutableResource;
import io.milton.resource.Resource;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;

import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersionException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.EdalAuthenticateException;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntity;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntityVersion;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataFile;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.FileSystemHandler;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.ExtXMLConfig;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.Property;

/**
 * A class enabling to browse all versions of a PrimaryDataFile using webDav.
 * 
 * @author benz, arendd
 * 
 */

public class PrimaryDataFileDirectoryVirtualResource extends
		PrimaryDataEntityResource implements CollectionResource,
		PutableResource {
	private ClientPrimaryDataFile file;

	public PrimaryDataFileDirectoryVirtualResource(String path,
			FileSystemHandler fileSystemHandler) throws RemoteException,
			PrimaryDataDirectoryException, NotBoundException,
			EdalAuthenticateException {
		super(path, fileSystemHandler);
		if (entity != null) {
			file = (ClientPrimaryDataFile) entity;
		}
	}

	public ClientPrimaryDataFile getFile() {
		return this.file;
	}

	@Override
	public boolean authorise(Request request, Method method, Auth auth) {
		boolean b = super.authorise(request, method, auth);
		if (entity != null) {
			file = (ClientPrimaryDataFile) entity;
		}
		return b;
	}

	@Override
	public Resource child(String childName) {
		if (entity == null) {
			return null;
		}
		Pattern p = Pattern.compile(".*\\/.*\\.v([0-9]+)\\..*$");
		Matcher m = p.matcher(childName);
		if (m.matches()) {
			try {
				long version = Long.valueOf(m.group(1));
				// files inside a directory are either
				Pattern property = Pattern
						.compile(".*\\.v[0-9]+\\.?[^\\.]*\\.properties\\.xml$");
				Matcher pm = property.matcher(childName);

				// virtual files
				if (!pm.matches()) {
					return new PrimaryDataFileVirtualResource(entity.getPath(),
							version, fileSystemHandler);
					// or property files
				} else {
					return new PrimaryDataEntityPropertyVirtualResource(
							entity.getCurrentVersion(), entity
									.getCurrentVersion().getRevision());
				}
			} catch (NumberFormatException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (RemoteException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (JAXBException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (MetaDataException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (PrimaryDataDirectoryException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (NotBoundException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (EdalAuthenticateException e) {
				ClientDataManager.logger.error("Failed to get child: "
						+ childName + "\nReason: " + e.toString());
			} catch (PrimaryDataEntityVersionException e) {
				ClientDataManager.logger.error("Failed to get child: " + file
						+ "\nReason: " + e.toString());
			}
		}

		return null;
	}

	@Override
	public List<? extends Resource> getChildren() {
		// TODO create base interface
		List<GetableResource> children = new ArrayList<GetableResource>();
		try {
			file = (ClientPrimaryDataFile) (this.fileSystemHandler
					.getEntity(path));
			SortedSet<ClientPrimaryDataEntityVersion> versions = file
					.getVersions();
			// this directory we only show history versions
			if (versions.size() > 1) {
				// PrimaryDataEntityVersion lastversion = versions.last();
				for (ClientPrimaryDataEntityVersion v : versions) {
					/*
					 * if(v.getRevision()==lastversion.getRevision()) {
					 * continue; }
					 */
					if (v.getRevision() != 0L && !v.isDeleted()) {
						children.add(new PrimaryDataFileVirtualResource(file
								.getPath(), v.getRevision(), fileSystemHandler));

						children.add(new PrimaryDataEntityPropertyVirtualResource(
								v, v.getRevision()));
					}
				}
			} else {
				/*
				 * if(!file.getCurrentVersion().isDeleted()) { children.add(new
				 * PrimaryDataFileResource(file.getPath(), 0L,
				 * fileSystemHandler));
				 * 
				 * children.add(new PrimaryDataEntityPropertyResource(file
				 * .getCurrentVersion(), file.getCurrentVersion()
				 * .getRevision())); }
				 */
			}

		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get children of: " + file
					+ "\nReason: " + e.toString());
		} catch (JAXBException e) {
			ClientDataManager.logger
					.error("Failed to create properties.xml for: " + file
							+ "\nReason: " + e.toString());
		} catch (MetaDataException e) {
			ClientDataManager.logger
					.error("Failed to create properties.xml for: " + file
							+ "\nReason: " + e.toString());
		} catch (PrimaryDataDirectoryException e) {
			ClientDataManager.logger.error("Failed to get children of: " + file
					+ "\nReason: " + e.toString());
		} catch (NotBoundException e) {
			ClientDataManager.logger.error("Failed to get children of: " + file
					+ "\nReason: " + e.toString());
		} catch (EdalAuthenticateException e) {
			ClientDataManager.logger.error("Failed to get children of: " + file
					+ "\nReason: " + e.toString());
		} catch (PrimaryDataEntityVersionException e) {
			ClientDataManager.logger.error("Failed to get child: " + file
					+ "\nReason: " + e.toString());
		}

		return children;
	}

	@Override
	public String getName() {
		try {
			return FileSystemHandler.VIRTUALFILEPREFIX + entity.getName();
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get name of: " + file
					+ "\nReason: " + e.toString());
		}

		return null;
	}

	@Override
	public Resource createNew(String newName, InputStream inputStream,
			Long length, String contentType) throws IOException,
			ConflictException, NotAuthorizedException, BadRequestException {
		if (newName.contains("properties.xml")) {
			ExtXMLConfig conf;
			try {
				conf = new ExtXMLConfig(Property.class);
				Object rawData = conf.load(inputStream);
				if (rawData != null) {
					Property metaData = (Property) rawData;
					Pattern property = Pattern
							.compile("(.*)\\.v[0-9]+\\.?[^\\.]*\\.(properties?\\.?xml|.*)$");
					Matcher pm = property.matcher(newName);
					if (pm.matches()) {
						ClientPrimaryDataEntity dirfile = fileSystemHandler
								.getEntity(file.getPath());
						if (dirfile != null) {
							MetaData newMetaData = dirfile.getMetaData()
									.clone();
							metaData.updateMetaData(newMetaData);
							dirfile.setMetaData(newMetaData);
							fileSystemHandler.removecache(file.getPath());

							PrimaryDataEntityPropertyVirtualResource virtualxmlresouce = new PrimaryDataEntityPropertyVirtualResource(
									dirfile.getCurrentVersion(), dirfile
											.getCurrentVersion().getRevision());
							return virtualxmlresouce;
						}
					}

				}
			} catch (JAXBException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (RemoteException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (CloneNotSupportedException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (PrimaryDataEntityVersionException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (MetaDataException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			} catch (PrimaryDataDirectoryException e) {
				ClientDataManager.logger
						.error("Failed to save properties-file: " + newName
								+ "\nReason: " + e.toString());
			}
		} else {
			throw new NotAuthorizedException("don't support this operation!",
					this);
		}

		return null;
	}

}
